// Package ir2实现了一种中间代码
//
// ir实现的中间代码，是四元式、线性的中间代码
//
// [OPEnum] 是中间代码的指令枚举
//
// [IrNode] 给定了一条ir指令的结构体定义
//
// # 指令
// 格式 op<arg1,arg2,result> []表示可选
//   - 变量声明 var<,,ast>
//   - 常量声明 const<,,ast>
//   - 赋值声明 mov<src,IncludeSrc,dest>
//   - 调用 call<callname,funcname,ParameNum and linefeed>
//   - 传参 papa<num,tmp,isNoEnd>
//   - 调用结束 stopcall<,,linefeed>
//   - 对象 obj<,,value>
//   - 函数 func<,,info>
//   - 右大括号 rbrace<,,>
//   - 加减乘除小于大于等于不等取余数 op<src1,src2,IncludeOpValue and linefeed> (Include operation values缩写成IncludeOpValue)
//   - 临时变量 tmpvar<name,type,>
//   - 返回 ret<[value],ReturnValueAfter,endIndex>
//   - for循环 for<,,>
//   - 分号 ;<,,>
//   - 逗号 comma<,,>
//   - 空行 linefeed<,,>
//   - 局部变量 localVar<Name,Type,>
//   - if分支 if<boolexpr,Nohaveboolexpr,>
//   - else分支 else<,,>
//   - else if 分支 if<boolexpr,Nohaveboolexpr,>
//   - 类型转换 TypeConvert<typ,value,>
//   - 一字段结构体 struct1field<field,,name>
//   - 二字段结构体 struct2field<field1,field2,name>
//   - 结构体声明 structdecl<,,name>
//   - 字段 field<field1,,>
//   - 2个字段 field<field1,field2,>
//   - 3个字段 field<field1,field2,field3>
//   - 赋值 assign<,,>
//   - 选择器左值和右值 left select right<left,right,>
//   - 选择器右值 select right<right,>
//   - 分配一个类型的内存 malloc<type,,linefeed>
package ir2

import (
	"fmt"
	"strconv"
	"strings"
	"unsafe"

	"gitee.com/u-language/u-language/ucom/ast"
	"gitee.com/u-language/u-language/ucom/astdata"
	"gitee.com/u-language/u-language/ucom/enum"
)

// IrNode 代表一条ir指令
type IrNode struct {
	Op                          OPEnum //操作码
	Arg1Obj                     string //第一操作数
	Arg2Obj                     string //第二操作数
	ResultObj                   string //运算结果的值
	Arg1Typ, Arg2Typ, ResultTyp string
	LineNum                     int //行号
}

func NewIr(Op OPEnum, LineNum int) IrNode {
	return IrNode{Op: Op, LineNum: LineNum}
}

func (n IrNode) String() string {
	var buf strings.Builder
	buf.WriteString("ir2.IrNode{Op: ")
	buf.WriteString(n.Op.String())
	buf.WriteString("LineNum：")
	buf.WriteString(strconv.Itoa(n.LineNum))
	buf.WriteString(" ")
	switch n.Op {
	case MOVOP:
		fmt.Fprintf(&buf, "Src:%s Result:%s ", n.Arg1Obj, n.ResultObj)
		fmt.Fprintf(&buf, "SrcTyp:%s ResultTyp:%s ", n.Arg1Typ, n.ResultTyp)
		fmt.Fprintf(&buf, "IncludeSrc:%t", n.Arg2Obj != enum.StrFalse)
	case ADDOP, SUBOP, MULOP, DIVOP, LessOp, GreaterOp, EqualOp, NoEqualOp, RemainOp:
		fmt.Fprintf(&buf, "Src1:%s Src2:%s Result:%s ", n.Arg1Obj, n.Arg2Obj, n.ResultObj)
		fmt.Fprintf(&buf, "Src1Typ:%s Src2Typ:%s ResultTyp:%s ", n.Arg1Typ, n.Arg2Typ, n.ResultTyp)
		fmt.Fprintf(&buf, "换行:%t", n.ResultTyp != enum.StrFalse)
	case FuncOP:
		fmt.Fprint(&buf, (**n.Func()).(*ast.FuncNode).Name)
	case VarOP:
		fmt.Fprint(&buf, (**n.Var()).String())
	case TmpVarOP:
		fmt.Fprintf(&buf, "Name:%s Type:%s", n.Arg1Obj, n.Arg2Obj)
	case CallOP:
		num, err := strconv.Atoi(n.ResultObj)
		fmt.Fprintf(&buf, "call:%s funcname:%s ParameNum:(num=%d err=%v) 换行:%t", (**n.FuncName()).FuncName(), n.Arg2Obj, num, err, n.ResultTyp != enum.StrFalse)
	case RetOp:
		fmt.Fprintf(&buf, "Value:%s ReturnValueAfter:%t endIndex:%s", n.Arg1Obj, n.Arg2Obj != enum.StrFalse, n.ResultObj)
	case PaPaOp:
		fmt.Fprintf(&buf, "num:%s tmp:%s", n.Arg1Obj, n.Arg2Obj)
	case ObjOP:
		fmt.Fprintf(&buf, "Value:%s", n.ResultObj)
	case LocalVarOp:
		fmt.Fprintf(&buf, "Name:%s Type:%s", n.Arg1Obj, n.Arg2Obj)
	case IfOp:
		fmt.Fprintf(&buf, "boolexpr:(%s,%s) Nohaveboolexpr:%t", n.Arg1Obj, n.Arg1Typ, n.Arg2Obj != enum.StrFalse)
	case ElseIfOp:
		fmt.Fprintf(&buf, "boolexpr:(%s,%s) Nohaveboolexpr:%t", n.Arg1Obj, n.Arg1Typ, n.Arg2Obj != enum.StrFalse)
	case RbraceOP, EndCallOp, ForOp, SemicolonOp, CommaOp, LbraceOp, LineFeedOp, RPARENOp, ElseOp, StructDeclStart, AssignOp: //不用特殊处理的
	case TypeConvertOp:
		fmt.Fprintf(&buf, "type:%s value:%s", n.Arg1Obj, n.Arg2Obj)
	case Field:
		fmt.Fprintf(&buf, "type:%s value:%s", (**n.Arg1ObjTyp()).Typ(), n.Arg1Obj)
	case Field3:
		fmt.Fprintf(&buf, "type1:%s value1:%s", (**n.Arg1ObjTyp()).Typ(), n.Arg1Obj)
		fmt.Fprintf(&buf, " type2:%s value2:%s", (**n.Arg2ObjTyp()).Typ(), n.Arg2Obj)
		fmt.Fprintf(&buf, " type3:%s value3:%s", (**n.ResultObjTyp()).Typ(), n.ResultObj)
	case Struct1Field: // 结构体1字段
		fmt.Fprintf(&buf, "type:%s value:%s", (**n.Arg1ObjTyp()).Typ(), n.Arg1Obj)
	case Struct2Field: // 结构体2字段
		fmt.Fprintf(&buf, "type1:%s value1:%s", (**n.Arg1ObjTyp()).Typ(), n.Arg1Obj)
		fmt.Fprintf(&buf, " type2:%s value2:%s", (**n.Arg2ObjTyp()).Typ(), n.Arg2Obj)
	case StructDeclEnd: // 结构体声明结束
		fmt.Fprintf(&buf, "name:%s", n.ResultObj)
	case SelectRight:
		fmt.Fprintf(&buf, "right:%s", n.Arg1Obj)
	case LeftSelectRight:
		fmt.Fprintf(&buf, "left:%s right:%s", n.Arg1Obj, n.Arg2Obj)
	case Malloc:
		fmt.Fprintf(&buf, "right:%+v 换行:%t", (**n.Arg1ObjExpr()), n.ResultObj != enum.StrFalse)
	default:
		panic(fmt.Errorf("未知的操作:%s", n.Op))
	}
	buf.WriteString("}")
	return buf.String()
}

func (n *IrNode) Func() **ast.Node {
	return ((**ast.Node)(unsafe.Pointer(&n.ResultObj)))
}

func (n *IrNode) FuncName() **ast.FuncNameNode {
	return ((**ast.FuncNameNode)(unsafe.Pointer(&n.Arg2Obj)))
}

func (n *IrNode) Var() **ast.VarNode {
	return ((**ast.VarNode)(unsafe.Pointer(&n.ResultObj)))
}

func (n *IrNode) Type() **astdata.Typ {
	return ((**astdata.Typ)(unsafe.Pointer(&n.Arg2Obj)))
}

func (n *IrNode) Arg1ObjTyp() **astdata.Typ {
	return ((**astdata.Typ)(unsafe.Pointer(&n.Arg1Typ)))
}

func (n *IrNode) Arg1ObjExpr() **ast.Expr {
	return ((**ast.Expr)(unsafe.Pointer(&n.Arg1Typ)))
}

func (n *IrNode) Arg2ObjTyp() **astdata.Typ {
	return ((**astdata.Typ)(unsafe.Pointer(&n.Arg2Typ)))
}

func (n *IrNode) ResultObjTyp() **astdata.Typ {
	return ((**astdata.Typ)(unsafe.Pointer(&n.ResultTyp)))
}
